/**
 * 定义了所需的各种数据结构、类，
 * 定义了所需的各种字符串常量。
*/
#include "basicutils.h"
using namespace std;

//版本号
const string version = "1.1";
//初始化的两个文件内容
const string aloha = "Aloha! here is SIMDISK V" + version;
const string guide = "You can use simple instructions to manage the disk.";
//命令使用方法
const string usage_input =
    "please input an instruction.\n";
const string usage_newfile =
    "Usage: newfile [new file name]\nLength of file name must shorter than 28.\n";
const string usage_md =
    "Usage: md [new dir name]\nLength of dir name must shorter than 28.\n";
const string usage_rd =
    "Usage: del [dir name]\nLength of dir name is shorter than 28.\nCan only delete folders.\n";
const string usage_cat =
    "Usage: cat [file name]\nLength of file name is shorter than 28.\n";
const string usage_cd =
    "Usage: cd [dir name]\nLength of dir name is shorter than 28.\n";
const string usage_del =
    "Usage: del [file name]\nLength of file name is shorter than 28.\nCan only delete files.\n";
const string usage_copy =
    "Usage: copy [source] [destiny]\nLength of file name is shorter than 28.\nif you want to copy files from host harddisk, add <host> before path of source file. eg:\ncopy <host>/home/chengyu/test.txt /test/data\n";
const string usage_check =
    "Usage: check\n";

//错误信息
const string err_toomuchpara = "Too much parameters.\n";
const string err_nofreeinode = "No free inodes. Delete something first.\n";
const string err_nofreeblk = "No free blocks. Delete something first.\n";
const string err_notafile = "It's not a file.\n";
const string err_notafolder = "It's not a folder.\n";
const string err_returnfromroot = "Already in /root .\n";
const string err_foldernf = "coulen't find such folder.\n";
const string err_filenf = "coulen't find such file.\n";
const string err_pmsdeny = "Permission Denied.\n";
const string err_ftoobig = "File is too big. Choose a smaller one.\n";
const string err_path = "Path error. Must start with root.\n";
const string err_nothing ="Nothing in this folder.\n";

string castChar2Bin(char c);
//i节点空闲管理位图
char *inodeBmap = new char[KB]{};
//文件块空闲管理位图
char *fblkBmap = new char[13 * KB]{};

//磁盘状态类，存储磁盘的状态信息
class DiskStatus
{
public:
    //磁盘大小（单位：块
    int diskSize = 0;
    //已使用的i节点
    int usedInode = 0;
    //已使用的文件块数量
    int usedBlk = 0;

    //将类信息转为字符串，用于显示状态
    string toString()
    {
        string s = "[Disk Status]\n";
        s += "disk size:\t";
        s += to_string(diskSize) + " blocks\n";
        s += "used inodes:\t";
        s += to_string(usedInode) + "\n";
        s += "used blocks:\t";
        s += to_string(usedBlk) + "\n";
        return s;
    }
};

//文件子项结构体
struct FolderItem
{
    int nodeNo;      //4B i节点编号
    char name[28]{}; //28B文件或文件夹名
};

//文件i节点类
class fileiNode
{
public:
    //i节点信息
    int nodeNo;       //4B i节点编号，即序号
    char fileSize;    //1B 文件大小（块
    char protectCode; //1B 保护码
    int createTime;   //4B 创建时间
    int lastCatTime;  //4B 上次打开时间
    //块地址
    int blockAddr[252]{};

    //添加新的文件块
    void addBlock(int blkaddr)
    {
        int fsize = castChar2Int(fileSize);
        if (fsize == 251)
        {
            cout << "Fail to add block. File already reached max size.\n";
            return;
        }
        blockAddr[fsize++] = blkaddr;
        fileSize = (char)fsize;
        return;
    }

    //将类信息转为字符串
    string toString(bool showblk = false)
    {
        string s = "[file inode info]\n";
        s += "node No.\t" + to_string(nodeNo) + "\n";
        s += "file size:\t" + to_string(castChar2Int(fileSize)) + "\n";
        s += "protect code:\t" + castChar2Bin(protectCode) + "\n";
        s += "create time:\t" + timeToString(createTime) + "\n";
        s += "last open time:\t" + timeToString(lastCatTime) + "\n";
        if (showblk)
        {
            s += "blocks:\n";
            for (int i = 0; i < castChar2Int(fileSize); ++i)
                s += to_string(blockAddr[i]) + "\t";
            s += "\n";
        }
        return s;
    }
};

//目录i节点类
class folderiNode
{
public:
    //i节点信息
    int nodeNo;            //4B i节点编号，即序号
    char folderName[28]{}; //28B文件夹名
    char folderSize;       //1B 文件夹大小（子项数量
    char protectCode;      //1B 保护码
    int createTime;        //4B 创建时间
    int lastCatTime;       //4B 上次打开时间
    //子目录及文件i节点
    FolderItem subItems[30];

    //添加新的子项
    bool addSubItem(int nodeNo, string name)
    {
        int fsize = castChar2Int(folderSize);
        if (fsize == 30)
        {
            cout << "failed. folder is full.\n";
            return false;
        }
        FolderItem fi;
        fi.nodeNo = nodeNo;
        strcpy(fi.name, name.c_str());
        subItems[fsize++] = fi;
        folderSize = (char)fsize;
        return true;
    }

    //获取该目录i节点在i节点区的位置
    int getPos()
    {
        return nodeNo - FOLDERSIGN;
    }

    //将类信息转为字符串
    string toString(bool showblk = false)
    {
        string fname = folderName;
        string s = "[folder inode info]\n";
        s += "node No.\t" + to_string(nodeNo) + "\n";
        s += "folder name:\t" + fname + "\n";
        s += "folder size:\t" + to_string(castChar2Int(folderSize)) + "\n";
        s += "protect code:\t" + castChar2Bin(protectCode) + "\n";
        s += "create time:\t" + timeToString(createTime) + "\n";
        s += "last open time:\t" + timeToString(lastCatTime) + "\n";
        string name;
        if (showblk)
        {
            for (int i = 0; i < castChar2Int(folderSize); ++i)
            {
                name = subItems[i].name;
                s += " [" + to_string(i) + "]\t";
                s += to_string(subItems[i].nodeNo) + "\t" + name + "\n";
            }
        }
        return s;
    }
};

/**
 * 共享内存结构体
 * workpath：工作目录
 * cmd：命令
 * userid：用户id
 * output：输出缓存
*/
struct shared_mem_st
{
    char workpath[MEMTEXT_SZ];
    char cmd[MEMTEXT_SZ];
    int userid;
    char output[MEMOUT_SZ];
};